package com.etcn.common.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.etcn.common.annotation.QueryCache;
import com.etcn.common.redis.RedisService;
import com.etcn.common.utils.JsonHandler;
import com.etcn.common.utils.StringUtil;
import com.etcn.common.utils.secret.MD5Util;

@Aspect
@Component
public class CacheAspect {
	private final Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private RedisService redisService;
	
	@Value("${userDataCache}")
	private boolean userDataCache;
	
	private Method getMethod(JoinPoint joinPoint) throws SecurityException, NoSuchMethodException {
		MethodSignature joinPointObject = (MethodSignature) joinPoint.getSignature();   
        Method m =  joinPointObject.getMethod();
        if(m.getDeclaringClass().isInterface()){
			m= joinPoint.getTarget().getClass().getDeclaredMethod(joinPoint.getSignature().getName(),
					m.getParameterTypes());
		}
        return m;
	}
	
	
	@Pointcut(value = "@annotation(com.etcn.common.annotation.QueryCache)")
    public void pointCuts() {}
	
	@Around(value = "pointCuts()")
	public Object cacheData(ProceedingJoinPoint joinPoint) throws Throwable {
		try{
			if (!userDataCache) {//如果未开启缓存 则直接关闭
				return joinPoint.proceed();
			}
			Method m = this.getMethod(joinPoint);
			QueryCache cache = m.getAnnotation(QueryCache.class);
			String keyPrefix = cache.keyPrefix();
			long expireTime = cache.expireTime();
			Object[] args = joinPoint.getArgs();
			String key = null;
			if(StringUtil.isNotEmpty(keyPrefix)){
				key = "querycache_"+keyPrefix;
			}else{
				key = "querycache_" + this.getKey(joinPoint.getTarget().getClass().getSimpleName() + "_" + m.getName(), args);
			}
			Object value = redisService.get(key);
			if(value != null){
				return value;
			}else{
				Object object = joinPoint.proceed();
				redisService.set(key, object, expireTime);
				return object;
			}
		}catch(Exception e){
			logger.error(joinPoint.getClass().getName() + "调用缓存失败",e);
			return joinPoint.proceed();
		}
	}
	
	private String getKey(String key,Object args[]) {
		if (args != null) {
			StringBuffer argsStr = new StringBuffer();
			for (Object arg : args) {
				if(arg != null){
					argsStr.append(arg.toString());
				}else{
					argsStr.append("null");
				}
			}
			key += "_" + MD5Util.Md5(argsStr.toString());
		}
		return key;
	}
}
